library(tidyverse)
── Attaching core tidyverse packages ────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────── tidyverse 2.0.0 ──
✔ dplyr 1.1.2 ✔ readr 2.1.4
✔ forcats 1.0.0 ✔ stringr 1.5.0
✔ ggplot2 3.4.2 ✔ tibble 3.2.1
✔ lubridate 1.9.2 ✔ tidyr 1.3.0
✔ purrr 1.0.1 ── Conflicts ──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────── tidyverse_conflicts() ──
✖ dplyr::filter() masks stats::filter()
✖ dplyr::lag() masks stats::lag()
ℹ Use the ]8;;http://conflicted.r-lib.org/conflicted package]8;; to force all conflicts to become errors
library(janitor)
Attaching package: ‘janitor’
The following objects are masked from ‘package:stats’:
chisq.test, fisher.test
steam <- read_csv("raw_data/steam_checkpoint.csv")
Rows: 26564 Columns: 22── Column specification ──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
Delimiter: ","
chr (8): name, developer, publisher, multiplayer, categories, genres, steamspy_tags, owners
dbl (8): appid, required_age, achievements, positive_ratings, negative_ratings, average_playtime, median_playtime, price
lgl (5): free_to_play, virtual_reality_support, windows_support, mac_support, linux_support
date (1): release_date
ℹ Use `spec()` to retrieve the full column specification for this data.
ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.
Where was i?
games_pre_cleaned <- read_csv("raw_data/Cleaned Data 2 GVGS&R.csv")
Rows: 6894 Columns: 15── Column specification ──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
Delimiter: ","
chr (5): Name, Genre, Publisher, Developer, Rating
dbl (10): Year_of_Release, NA_Sales, EU_Sales, JP_Sales, Other_Sales, Global_Sales, Critic_Score, Critic_Count, User_Score, User_Count
ℹ Use `spec()` to retrieve the full column specification for this data.
ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.
games_pre_cleaned
How dare you do the work for me
games_raw <- read_csv("raw_data/Raw Data GVGS&R.csv")
Rows: 16719 Columns: 16── Column specification ──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
Delimiter: ","
chr (8): Name, Platform, Year_of_Release, Genre, Publisher, User_Score, Developer, Rating
dbl (8): NA_Sales, EU_Sales, JP_Sales, Other_Sales, Global_Sales, Critic_Score, Critic_Count, User_Count
ℹ Use `spec()` to retrieve the full column specification for this data.
ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.
games_raw %>%
filter(Name == "Minecraft")
Why does everyone have the same dataset
back to steam i guess
steam
steam %>%
distinct(genres)
Already have F2P covered by another column, so we can drop that in
genres
steam %>%
mutate(genres = str_remove_all(genres, "Free to Play")) %>%
filter(free_to_play == TRUE)
Is this worth doing? Duplicated info doesn’t hurt i suppose - leave
it for now
single player?
steam <- steam %>%
mutate(singleplayer = case_when(
str_detect(categories, "Single-player") ~ TRUE,
str_detect(steamspy_tags, "Singleplayer") ~ TRUE,
TRUE ~ FALSE
),.before = multiplayer)
steam %>%
filter(free_to_play == TRUE)
steam
# adding column to simplify ratings
steam <- steam %>%
mutate(total_reviews = positive_ratings + negative_ratings) %>%
arrange(desc(total_reviews)) %>%
mutate(percent_positive_reviews = positive_ratings / total_reviews) %>%
mutate(general_rating = case_when(
total_reviews > 1000 & percent_positive_reviews >= 0.95 ~ "Extremely Positive",
total_reviews > 1000 & percent_positive_reviews >= 0.75 ~ "Positive",
total_reviews > 1000 & percent_positive_reviews >= 0.55 ~ "Mostly Positive",
total_reviews > 1000 & percent_positive_reviews >= 0.50 ~ "Mixed" ,
total_reviews > 1000 & percent_positive_reviews >= 0.35 ~ " Mostly Negative",
total_reviews > 1000 & percent_positive_reviews >= 0.15 ~ "Negative",
total_reviews > 1000 & percent_positive_reviews < 0.15 ~ "Extremely Negative",
positive_ratings == 0 ~ "No Positive Reviews",
negative_ratings == 0 ~ "No Negative Reviews",
positive_ratings & negative_ratings == 0 ~ "No Reviews",
total_reviews < 1000 ~ "Not Enough Reviews",
TRUE ~ "No Data"
),.before = positive_ratings) %>%
select(-percent_positive_reviews)
backloggd <- read_csv("clean_data/backloggd_clean.csv")
Rows: 1115 Columns: 15── Column specification ──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
Delimiter: ","
chr (9): title, team, genre_tag, genre_tag_2, genre_tag_3, genre_tag_4, genre_tag_5, genre_tag_6, genre_tag_7
dbl (5): years_since_release, rating, number_of_reviews, wishlist, plays
date (1): release_date
ℹ Use `spec()` to retrieve the full column specification for this data.
ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.
backloggd
games_raw <- games_raw %>%
clean_names()
# Platform isn't a genre - correcting
games_raw <- games_raw %>%
mutate(genre = case_when(
genre == "Platform" ~ "Platformer",
TRUE ~ genre
))
nintendo_published <- games_raw %>%
filter(publisher == "Nintendo")
genre_publisher_sales <- games_raw %>%
group_by(publisher, genre) %>%
summarise(sum(global_sales)) %>%
arrange(desc(`sum(global_sales)`))
`summarise()` has grouped output by 'publisher'. You can override using the `.groups` argument.
write_csv(genre_publisher_sales, "clean_data/genre_by_publisher.csv")
genre_publisher_sales %>%
filter(publisher == "From Software")
games_raw %>%
distinct(rating)
# clarifying that the rating is for ESRP - the american system
games_raw <- games_raw %>%
rename("esrp" = "rating")
# Adding PEGI equivalent
games_raw <- games_raw %>%
mutate(pegi_equivalent = case_when(
esrp == "EC" ~ "3",
esrp == "E" ~ "7",
esrp == "E10+" ~ "12",
esrp == "T" ~ "16",
esrp == "M" ~ "18",
esrp == "AO" ~ "18",
esrp == "K-A" ~ "7",
esrp == "RP" ~ "No Rating",
TRUE ~ "No Rating Found"
))
total_sales_by_genre <- games_raw %>%
group_by(genre) %>%
summarise(sum(global_sales)) %>%
rename("total_sales" = "sum(global_sales)") %>%
arrange(desc(total_sales))
total_sales_by_genre <- total_sales_by_genre %>%
drop_na()
games_raw
breakdown_sales_by_genre <- games_raw %>%
group_by(genre) %>%
summarise(sum(na_sales), sum(eu_sales), sum(jp_sales), sum(other_sales)) %>%
rename("total_na_sales"= "sum(na_sales)", "total_eu_sales" = "sum(eu_sales)", "total_jp_sales" = "sum(jp_sales)", "total_other_sales" = "sum(other_sales)")
total_sales_by_genre # this seems to have some rounding differences compared to breakdown, so i'll retire this one
how does the sales for the top 3 genres look in each region?
breakdown_sales_by_genre <- breakdown_sales_by_genre %>%
group_by(genre) %>%
mutate(total_sales = sum(total_na_sales + total_eu_sales + total_jp_sales + total_other_sales)) %>%
drop_na()
breakdown_sales_by_genre %>%
filter(genre %in% c("Action", "Sports", "Shooter")) %>%
ggplot(aes(x = total_sales, y = genre))+
geom_col() +
geom_col(aes(x = total_na_sales), fill = "green")+
geom_col(aes(x = total_eu_sales), fill = "red") +
geom_col(aes(x = total_jp_sales), fill = "blue")

# this looks shit
What about trends? How did each genres sales adjust every 5 or so
years?
games_raw %>%
filter(year_of_release == "2016")
games_raw %>%
mutate(year_of_release = as.integer(year_of_release)) %>%
distinct(year_of_release) %>%
arrange(year_of_release)
Warning: There was 1 warning in `mutate()`.
ℹ In argument: `year_of_release = as.integer(year_of_release)`.
Caused by warning:
! NAs introduced by coercion
sales_2019 <- read_csv("raw_data/sales-2019.csv")
Rows: 55792 Columns: 23── Column specification ──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
Delimiter: ","
chr (10): Name, basename, Genre, ESRB_Rating, Platform, Publisher, Developer, Last_Update, url, img_url
dbl (12): Rank, Critic_Score, User_Score, Total_Shipped, Global_Sales, NA_Sales, PAL_Sales, JP_Sales, Other_Sales, Year, status, Vgchartzscore
lgl (1): VGChartz_Score
ℹ Use `spec()` to retrieve the full column specification for this data.
ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.
sales_2019 %>%
distinct(Year) %>%
arrange(desc(Year))
sales_2019 %>%
filter(Year == "2019") %>%
select(Name, Year, Platform)
# data for 2020 is total nonsense. Some information in 2019 is incorrect.
Going off the fact that there is the majority of usable information
i am able to get is from 2019 or before, we’re just going to pretend
we’re living in an
alternative 2019
As such, I am dropping all data from 2020 in this dataset
sales_2019 <- sales_2019 %>%
filter(Year != "2020")
Looking at backloggd again
backloggd
# creating a range_rating column to reduce noise when it comes to plotting results
backlogged <- backloggd %>%
mutate(rating_range = case_when(
rating < 5 & rating >= 4 ~ "4+",
rating < 4 & rating >= 3 ~ "3 to 4",
rating < 3 & rating >= 2 ~ "2 to 3",
rating < 2 & rating >= 1 ~ "1 to 2",
rating < 1 ~ ">1",
TRUE ~ "No rating"
))
DIFFICULTIES WITH THE DATA
After having little success attempting to get a more up to date data
set, i’ve decided to stick with what I already have - Given more time, i
would have liked to have run the steam/steam spy script to scrape all
the steam data, but unfortunately i couldn’t commit 3 days to it. There
doesn’t seem to be much in the way of modern sales data, with most
companies not releasing figures unless its to do with a milestone.
Genres are quite vague - While it would be nice to have tags like “Open
World”, “Rouge-like/lite”, we instead mostly have “Action” “Adventure”,
“Indie”, which are not hugely descriptive. This might make recommending
a genre to work on harder
DAY 3
sales_2019 %>%
summary()
Rank Name basename Genre ESRB_Rating Platform Publisher Developer VGChartz_Score Critic_Score
Min. : 1 Length:54482 Length:54482 Length:54482 Length:54482 Length:54482 Length:54482 Length:54482 Mode:logical Min. : 1.00
1st Qu.:13638 Class :character Class :character Class :character Class :character Class :character Class :character Class :character NA's:54482 1st Qu.: 6.40
Median :27421 Mode :character Mode :character Mode :character Mode :character Mode :character Mode :character Mode :character Median : 7.50
Mean :27465 Mean : 7.21
3rd Qu.:41202 3rd Qu.: 8.30
Max. :55791 Max. :10.00
NA's :47952
User_Score Total_Shipped Global_Sales NA_Sales PAL_Sales JP_Sales Other_Sales Year Last_Update url status
Min. : 2.00 Min. : 0.03 Min. : 0.00 Min. :0.00 Min. :0.00 Min. :0.00 Min. :0.00 Min. :1970 Length:54482 Length:54482 Min. :1
1st Qu.: 7.80 1st Qu.: 0.20 1st Qu.: 0.03 1st Qu.:0.05 1st Qu.:0.01 1st Qu.:0.02 1st Qu.:0.00 1st Qu.:2000 Class :character Class :character 1st Qu.:1
Median : 8.50 Median : 0.59 Median : 0.12 Median :0.12 Median :0.04 Median :0.05 Median :0.01 Median :2008 Mode :character Mode :character Median :1
Mean : 8.27 Mean : 1.89 Mean : 0.37 Mean :0.28 Mean :0.16 Mean :0.11 Mean :0.04 Mean :2006 Mean :1
3rd Qu.: 9.20 3rd Qu.: 1.80 3rd Qu.: 0.36 3rd Qu.:0.29 3rd Qu.:0.14 3rd Qu.:0.12 3rd Qu.:0.04 3rd Qu.:2011 3rd Qu.:1
Max. :10.00 Max. :82.86 Max. :20.32 Max. :9.76 Max. :9.85 Max. :2.69 Max. :3.12 Max. :2019 Max. :1
NA's :54154 NA's :52661 NA's :35132 NA's :41528 NA's :41334 NA's :47458 NA's :39005
Vgchartzscore img_url
Min. :2.60 Length:54482
1st Qu.:6.90 Class :character
Median :7.90 Mode :character
Mean :7.49
3rd Qu.:8.50
Max. :9.60
NA's :53726
All of the VGchartz scores are empty, so it can go. Also, same as
above, there’s no such genre as Platform
1970 is nonsense. dropping entire year
ggsave("Visualisations/2019_genres_inc_misc.png")
Saving 7 x 7 in image
ggsave("Visualisations/2019_genres_excl_misc.png")
Saving 7 x 7 in image
This is slightly concerning - a lot of these titles could easily have
a genre that isn’t the cure-all “Misc” - Include both graphs - one with
misc, one excluding it
What about a similar plot for steam games?
steam_years <- steam_years %>%
separate(col = genres, sep = ";", into = paste0("Genre", seq_len(max(nchar(.$genres))))) %>% # this is absolutely horrendous, but it gets me all the genres into separate columns so whatever
select(-Genre14:-Genre180) %>%
pivot_longer(cols = Genre1:Genre13, names_to = "genres") %>%
drop_na(value) %>% # ok now we can make the year intervals and group them to find what genres were popular
mutate(year_range = case_when(
release_year <= 2019 & release_year >= 2016 ~ "2016 - 2019",
release_year <= 2015 & release_year >= 2012 ~ "2012 - 2015",
release_year <= 2011 & release_year >= 2009 ~ "2009 - 2011",
release_year <= 2008 & release_year >= 2005 ~ "2005 - 2008",
release_year <= 2004 & release_year>= 2000 ~ "2000 - 2004",
release_year < 2001 ~ "Before 2000",
TRUE ~ "this shouldnt appear"
),.after = release_year)
Warning: Expected 180 pieces. Missing pieces filled with `NA` in 26564 rows [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, ...].

ggsave("Visualisations/steam_genres_2009_on.png")
Saving 7 x 7 in image
backloggd_genres %>%
pivot_longer(cols = genre_tag:genre_tag_7, names_to = "list", values_to = "genre") %>%
drop_na(genre)
Error in pivot_longer(., cols = genre_tag:genre_tag_7, names_to = "list", :
object 'backloggd_genres' not found
ggsave("Visualisations/backloggd_genres.png")
Saving 7 x 7 in image
We have established that Indie, Action and Adventure games seem to
be the most popular - But what other elements make them popular?
Note: Action and Adventure are pretty interchangable nothing terms
that describe like 90% of titles but oh well
Like would you compare Nier Automata to Donkey Kong Jungle Beat? I
wouldn’t but who am i to say
and for comparison
Make a model that tries to guess if a game is positively rated?
{r} # steam_model_base <- steam %>% # separate(col = genres, sep = ";", into = paste0("Genre", seq_len(max(nchar(.$genres))))) %>% # select(-Genre14:-Genre180) #
{r} # steam_model_base %>% # separate(col = categories, sep = ";", into = paste0("categories", seq_len(max(nchar(.$categories))))) %>% # select(-categories21:-categories299) #
{r} # steam %>% # select(categories) %>% # mutate(length_cat = nchar(categories)) %>% # arrange(desc(length_cat)) #
This is idiotic. There are far too many variables. Might mutate a few
of these into logicals, like controller support
Ok so what do i need to do tomorrow - Continue working on
visualisations, maybe make a model that tries to see what factors make
games do well on steam?
LS0tDQp0aXRsZTogIkRBWSAyIg0Kb3V0cHV0OiBodG1sX25vdGVib29rDQotLS0NCg0KYGBge3J9DQpsaWJyYXJ5KHRpZHl2ZXJzZSkNCmxpYnJhcnkoamFuaXRvcikNCg0Kc3RlYW0gPC0gcmVhZF9jc3YoInJhd19kYXRhL3N0ZWFtX2NoZWNrcG9pbnQuY3N2IikNCmBgYA0KDQpXaGVyZSB3YXMgaT8NCg0KYGBge3J9DQpnYW1lc19wcmVfY2xlYW5lZCA8LSByZWFkX2NzdigicmF3X2RhdGEvQ2xlYW5lZCBEYXRhIDIgR1ZHUyZSLmNzdiIpDQpgYGANCg0KYGBge3J9DQpnYW1lc19wcmVfY2xlYW5lZA0KYGBgDQpIb3cgZGFyZSB5b3UgZG8gdGhlIHdvcmsgZm9yIG1lDQoNCmBgYHtyfQ0KZ2FtZXNfcmF3IDwtIHJlYWRfY3N2KCJyYXdfZGF0YS9SYXcgRGF0YSBHVkdTJlIuY3N2IikNCmBgYA0KDQpgYGB7cn0NCmdhbWVzX3JhdyAlPiUgDQogIGZpbHRlcihOYW1lID09ICJNaW5lY3JhZnQiKQ0KYGBgDQpXaHkgZG9lcyBldmVyeW9uZSBoYXZlIHRoZSBzYW1lIGRhdGFzZXQNCg0KYmFjayB0byBzdGVhbSBpIGd1ZXNzDQoNCmBgYHtyfQ0Kc3RlYW0NCmBgYA0KDQpgYGB7cn0NCnN0ZWFtICU+JSANCiAgZGlzdGluY3QoZ2VucmVzKQ0KYGBgDQoNCkFscmVhZHkgaGF2ZSBGMlAgY292ZXJlZCBieSBhbm90aGVyIGNvbHVtbiwgc28gd2UgY2FuIGRyb3AgdGhhdCBpbiBnZW5yZXMNCg0KYGBge3J9DQpzdGVhbSAlPiUgDQogIG11dGF0ZShnZW5yZXMgPSBzdHJfcmVtb3ZlX2FsbChnZW5yZXMsICJGcmVlIHRvIFBsYXkiKSkgJT4lIA0KICBmaWx0ZXIoZnJlZV90b19wbGF5ID09IFRSVUUpDQpgYGANCg0KSXMgdGhpcyB3b3J0aCBkb2luZz8NCkR1cGxpY2F0ZWQgaW5mbyBkb2Vzbid0IGh1cnQgaSBzdXBwb3NlIC0gbGVhdmUgaXQgZm9yIG5vdw0KDQpzaW5nbGUgcGxheWVyPw0KDQpgYGB7cn0NCnN0ZWFtIDwtIHN0ZWFtICU+JSANCiAgbXV0YXRlKHNpbmdsZXBsYXllciA9IGNhc2Vfd2hlbigNCiAgICBzdHJfZGV0ZWN0KGNhdGVnb3JpZXMsICJTaW5nbGUtcGxheWVyIikgfiBUUlVFLA0KICAgIHN0cl9kZXRlY3Qoc3RlYW1zcHlfdGFncywgIlNpbmdsZXBsYXllciIpIH4gVFJVRSwNCiAgICBUUlVFIH4gRkFMU0UNCiAgKSwuYmVmb3JlID0gbXVsdGlwbGF5ZXIpDQpgYGANCg0KYGBge3J9DQpzdGVhbSAlPiUgDQogIGZpbHRlcihmcmVlX3RvX3BsYXkgPT0gVFJVRSkgDQpgYGANCmBgYHtyfQ0Kc3RlYW0NCmBgYA0KYGBge3J9DQojIGFkZGluZyBjb2x1bW4gdG8gc2ltcGxpZnkgcmF0aW5ncyANCnN0ZWFtIDwtIHN0ZWFtICU+JSANCiAgbXV0YXRlKHRvdGFsX3Jldmlld3MgPSBwb3NpdGl2ZV9yYXRpbmdzICsgIG5lZ2F0aXZlX3JhdGluZ3MpICU+JSANCiAgYXJyYW5nZShkZXNjKHRvdGFsX3Jldmlld3MpKSAlPiUgDQogIG11dGF0ZShwZXJjZW50X3Bvc2l0aXZlX3Jldmlld3MgPSBwb3NpdGl2ZV9yYXRpbmdzIC8gdG90YWxfcmV2aWV3cykgJT4lIA0KICBtdXRhdGUoZ2VuZXJhbF9yYXRpbmcgPSBjYXNlX3doZW4oDQogICAgdG90YWxfcmV2aWV3cyA+IDEwMDAgJiBwZXJjZW50X3Bvc2l0aXZlX3Jldmlld3MgPj0gMC45NSB+ICJFeHRyZW1lbHkgUG9zaXRpdmUiLA0KICAgIHRvdGFsX3Jldmlld3MgPiAxMDAwICYgcGVyY2VudF9wb3NpdGl2ZV9yZXZpZXdzID49IDAuNzUgfiAiUG9zaXRpdmUiLA0KICAgIHRvdGFsX3Jldmlld3MgPiAxMDAwICYgcGVyY2VudF9wb3NpdGl2ZV9yZXZpZXdzID49IDAuNTUgfiAiTW9zdGx5IFBvc2l0aXZlIiwNCiAgICB0b3RhbF9yZXZpZXdzID4gMTAwMCAmIHBlcmNlbnRfcG9zaXRpdmVfcmV2aWV3cyA+PSAwLjUwIH4gIk1peGVkIiAsDQogICAgdG90YWxfcmV2aWV3cyA+IDEwMDAgJiBwZXJjZW50X3Bvc2l0aXZlX3Jldmlld3MgPj0gMC4zNSB+ICIgTW9zdGx5IE5lZ2F0aXZlIiwNCiAgICB0b3RhbF9yZXZpZXdzID4gMTAwMCAmIHBlcmNlbnRfcG9zaXRpdmVfcmV2aWV3cyA+PSAwLjE1IH4gIk5lZ2F0aXZlIiwNCiAgICB0b3RhbF9yZXZpZXdzID4gMTAwMCAmIHBlcmNlbnRfcG9zaXRpdmVfcmV2aWV3cyA8IDAuMTUgfiAiRXh0cmVtZWx5IE5lZ2F0aXZlIiwNCiAgICBwb3NpdGl2ZV9yYXRpbmdzID09IDAgfiAiTm8gUG9zaXRpdmUgUmV2aWV3cyIsDQogICAgbmVnYXRpdmVfcmF0aW5ncyA9PSAwIH4gIk5vIE5lZ2F0aXZlIFJldmlld3MiLA0KICAgIHBvc2l0aXZlX3JhdGluZ3MgJiBuZWdhdGl2ZV9yYXRpbmdzID09IDAgfiAiTm8gUmV2aWV3cyIsDQogICAgdG90YWxfcmV2aWV3cyA8IDEwMDAgfiAiTm90IEVub3VnaCBSZXZpZXdzIiwNCiAgICBUUlVFIH4gIk5vIERhdGEiDQogICksLmJlZm9yZSA9IHBvc2l0aXZlX3JhdGluZ3MpICU+JSANCiAgc2VsZWN0KC1wZXJjZW50X3Bvc2l0aXZlX3Jldmlld3MpDQpgYGANCg0KDQoNCmBgYHtyfQ0KYmFja2xvZ2dkIDwtIHJlYWRfY3N2KCJjbGVhbl9kYXRhL2JhY2tsb2dnZF9jbGVhbi5jc3YiKQ0KYGBgDQoNCmBgYHtyfQ0KYmFja2xvZ2dkDQpgYGANCg0KDQpgYGB7cn0NCmdhbWVzX3JhdyA8LSBnYW1lc19yYXcgJT4lIA0KICBjbGVhbl9uYW1lcygpDQpgYGANCg0KYGBge3J9DQojIFBsYXRmb3JtIGlzbid0IGEgZ2VucmUgLSBjb3JyZWN0aW5nDQpnYW1lc19yYXcgPC0gZ2FtZXNfcmF3ICU+JSANCiAgbXV0YXRlKGdlbnJlID0gY2FzZV93aGVuKA0KICAgIGdlbnJlID09ICJQbGF0Zm9ybSIgfiAiUGxhdGZvcm1lciIsDQogICAgVFJVRSB+IGdlbnJlDQogICkpDQpgYGANCg0KYGBge3J9DQpuaW50ZW5kb19wdWJsaXNoZWQgPC0gZ2FtZXNfcmF3ICU+JSANCiAgZmlsdGVyKHB1Ymxpc2hlciA9PSAiTmludGVuZG8iKQ0KYGBgDQoNCmBgYHtyfQ0KZ2VucmVfcHVibGlzaGVyX3NhbGVzIDwtIGdhbWVzX3JhdyAlPiUgIA0KICBncm91cF9ieShwdWJsaXNoZXIsIGdlbnJlKSAlPiUgDQogIHN1bW1hcmlzZShzdW0oZ2xvYmFsX3NhbGVzKSkgJT4lIA0KICBhcnJhbmdlKGRlc2MoYHN1bShnbG9iYWxfc2FsZXMpYCkpDQpgYGANCmBgYHtyfQ0Kd3JpdGVfY3N2KGdlbnJlX3B1Ymxpc2hlcl9zYWxlcywgImNsZWFuX2RhdGEvZ2VucmVfYnlfcHVibGlzaGVyLmNzdiIpDQpgYGANCg0KYGBge3J9DQpnZW5yZV9wdWJsaXNoZXJfc2FsZXMgJT4lIA0KICBmaWx0ZXIocHVibGlzaGVyID09ICJGcm9tIFNvZnR3YXJlIikNCmBgYA0KDQpgYGB7cn0NCmdhbWVzX3JhdyAlPiUgDQogIGRpc3RpbmN0KHJhdGluZykNCmBgYA0KDQoNCmBgYHtyfQ0KIyBjbGFyaWZ5aW5nIHRoYXQgdGhlIHJhdGluZyBpcyBmb3IgRVNSUCAtIHRoZSBhbWVyaWNhbiBzeXN0ZW0NCmdhbWVzX3JhdyA8LSBnYW1lc19yYXcgJT4lIA0KICByZW5hbWUoImVzcnAiID0gInJhdGluZyIpIA0KYGBgDQoNCmBgYHtyfQ0KIyBBZGRpbmcgUEVHSSBlcXVpdmFsZW50IA0KZ2FtZXNfcmF3IDwtIGdhbWVzX3JhdyAlPiUgDQogIG11dGF0ZShwZWdpX2VxdWl2YWxlbnQgPSBjYXNlX3doZW4oDQogICAgZXNycCA9PSAiRUMiIH4gIjMiLA0KICAgIGVzcnAgPT0gIkUiIH4gIjciLA0KICAgIGVzcnAgPT0gIkUxMCsiIH4gIjEyIiwNCiAgICBlc3JwID09ICJUIiB+ICIxNiIsDQogICAgZXNycCA9PSAiTSIgfiAiMTgiLA0KICAgIGVzcnAgPT0gIkFPIiB+ICIxOCIsDQogICAgZXNycCA9PSAiSy1BIiB+ICI3IiwNCiAgICBlc3JwID09ICJSUCIgfiAiTm8gUmF0aW5nIiwNCiAgICBUUlVFIH4gIk5vIFJhdGluZyBGb3VuZCINCiAgKSkgDQogIA0KYGBgDQoNCmBgYHtyfQ0KdG90YWxfc2FsZXNfYnlfZ2VucmUgPC0gZ2FtZXNfcmF3ICU+JSANCiAgZ3JvdXBfYnkoZ2VucmUpICU+JSANCiAgc3VtbWFyaXNlKHN1bShnbG9iYWxfc2FsZXMpKSAlPiUgDQogIHJlbmFtZSgidG90YWxfc2FsZXMiID0gInN1bShnbG9iYWxfc2FsZXMpIikgJT4lIA0KICBhcnJhbmdlKGRlc2ModG90YWxfc2FsZXMpKQ0KYGBgDQoNCmBgYHtyfQ0KdG90YWxfc2FsZXNfYnlfZ2VucmUgPC0gdG90YWxfc2FsZXNfYnlfZ2VucmUgJT4lIA0KICBkcm9wX25hKCkNCmBgYA0KDQpgYGB7cn0NCmdhbWVzX3JhdyANCmBgYA0KDQpgYGB7cn0NCmJyZWFrZG93bl9zYWxlc19ieV9nZW5yZSA8LSBnYW1lc19yYXcgJT4lIA0KICBncm91cF9ieShnZW5yZSkgJT4lIA0KICBzdW1tYXJpc2Uoc3VtKG5hX3NhbGVzKSwgc3VtKGV1X3NhbGVzKSwgc3VtKGpwX3NhbGVzKSwgc3VtKG90aGVyX3NhbGVzKSkgJT4lIA0KICByZW5hbWUoInRvdGFsX25hX3NhbGVzIj0gInN1bShuYV9zYWxlcykiLCAidG90YWxfZXVfc2FsZXMiID0gInN1bShldV9zYWxlcykiLCAidG90YWxfanBfc2FsZXMiID0gInN1bShqcF9zYWxlcykiLCAidG90YWxfb3RoZXJfc2FsZXMiID0gInN1bShvdGhlcl9zYWxlcykiKQ0KYGBgDQoNCmBgYHtyfQ0KdG90YWxfc2FsZXNfYnlfZ2VucmUgIyB0aGlzIHNlZW1zIHRvIGhhdmUgc29tZSByb3VuZGluZyBkaWZmZXJlbmNlcyBjb21wYXJlZCB0byBicmVha2Rvd24sIHNvIGknbGwgcmV0aXJlIHRoaXMgb25lIA0KYGBgDQpob3cgZG9lcyB0aGUgc2FsZXMgZm9yIHRoZSB0b3AgMyBnZW5yZXMgbG9vayBpbiBlYWNoIHJlZ2lvbj8NCg0KDQpgYGB7cn0NCmJyZWFrZG93bl9zYWxlc19ieV9nZW5yZSA8LSBicmVha2Rvd25fc2FsZXNfYnlfZ2VucmUgJT4lIA0KICBncm91cF9ieShnZW5yZSkgJT4lIA0KICBtdXRhdGUodG90YWxfc2FsZXMgPSBzdW0odG90YWxfbmFfc2FsZXMgKyB0b3RhbF9ldV9zYWxlcyArIHRvdGFsX2pwX3NhbGVzICsgdG90YWxfb3RoZXJfc2FsZXMpKSAlPiUgDQogIGRyb3BfbmEoKQ0KYGBgDQpgYGB7cn0NCg0KYnJlYWtkb3duX3NhbGVzX2J5X2dlbnJlICU+JSANCiAgZmlsdGVyKGdlbnJlICVpbiUgYygiQWN0aW9uIiwgIlNwb3J0cyIsICJTaG9vdGVyIikpICU+JSANCiAgZ2dwbG90KGFlcyh4ID0gdG90YWxfc2FsZXMsIHkgPSBnZW5yZSkpKw0KICBnZW9tX2NvbCgpICsNCiAgZ2VvbV9jb2woYWVzKHggPSB0b3RhbF9uYV9zYWxlcyksIGZpbGwgPSAiZ3JlZW4iKSsNCiAgZ2VvbV9jb2woYWVzKHggPSB0b3RhbF9ldV9zYWxlcyksIGZpbGwgPSAicmVkIikgKw0KICBnZW9tX2NvbChhZXMoeCA9IHRvdGFsX2pwX3NhbGVzKSwgZmlsbCA9ICJibHVlIikgDQoNCiMgdGhpcyBsb29rcyBzaGl0DQpgYGANCg0KV2hhdCBhYm91dCB0cmVuZHM/IEhvdyBkaWQgZWFjaCBnZW5yZXMgc2FsZXMgYWRqdXN0IGV2ZXJ5IDUgb3Igc28geWVhcnM/DQoNCmBgYHtyfQ0KZ2FtZXNfcmF3ICU+JSANCiAgZmlsdGVyKHllYXJfb2ZfcmVsZWFzZSA9PSAiMjAxNiIpDQoNCmdhbWVzX3JhdyAlPiUgDQogIG11dGF0ZSh5ZWFyX29mX3JlbGVhc2UgPSBhcy5pbnRlZ2VyKHllYXJfb2ZfcmVsZWFzZSkpICU+JSANCiAgZGlzdGluY3QoeWVhcl9vZl9yZWxlYXNlKSAlPiUgDQogIGFycmFuZ2UoeWVhcl9vZl9yZWxlYXNlKQ0KDQpgYGANCg0KYGBge3J9DQpzYWxlc18yMDE5IDwtIHJlYWRfY3N2KCJyYXdfZGF0YS9zYWxlcy0yMDE5LmNzdiIpDQpgYGANCg0KYGBge3J9DQpzYWxlc18yMDE5ICU+JSANCiAgZGlzdGluY3QoWWVhcikgJT4lIA0KICBhcnJhbmdlKGRlc2MoWWVhcikpDQpgYGANCmBgYHtyfQ0Kc2FsZXNfMjAxOSAlPiUgDQogIGZpbHRlcihZZWFyID09ICIyMDE5IikgJT4lIA0KICBzZWxlY3QoTmFtZSwgWWVhciwgUGxhdGZvcm0pDQoNCiMgZGF0YSBmb3IgMjAyMCBpcyB0b3RhbCBub25zZW5zZS4gU29tZSBpbmZvcm1hdGlvbiBpbiAyMDE5IGlzIGluY29ycmVjdC4NCmBgYA0KIyBHb2luZyBvZmYgdGhlIGZhY3QgdGhhdCB0aGVyZSBpcyB0aGUgbWFqb3JpdHkgb2YgdXNhYmxlIGluZm9ybWF0aW9uIGkgYW0gYWJsZSB0byBnZXQgaXMgZnJvbSAyMDE5IG9yIGJlZm9yZSwgd2UncmUganVzdCBnb2luZyB0byBwcmV0ZW5kIHdlJ3JlIGxpdmluZyBpbiBhbiANCiMgYWx0ZXJuYXRpdmUgMjAxOQ0KDQpBcyBzdWNoLCBJIGFtIGRyb3BwaW5nIGFsbCBkYXRhIGZyb20gMjAyMCBpbiB0aGlzIGRhdGFzZXQgDQoNCmBgYHtyfQ0Kc2FsZXNfMjAxOSA8LSBzYWxlc18yMDE5ICU+JSANCiAgZmlsdGVyKFllYXIgIT0gIjIwMjAiKQ0KYGBgDQoNCiMgTG9va2luZyBhdCBiYWNrbG9nZ2QgYWdhaW4NCg0KYGBge3J9DQpiYWNrbG9nZ2QNCmBgYA0KYGBge3J9DQojIGNyZWF0aW5nIGEgcmFuZ2VfcmF0aW5nIGNvbHVtbiB0byByZWR1Y2Ugbm9pc2Ugd2hlbiBpdCBjb21lcyB0byBwbG90dGluZyByZXN1bHRzDQpiYWNrbG9nZ2VkIDwtIGJhY2tsb2dnZCAlPiUgDQogIG11dGF0ZShyYXRpbmdfcmFuZ2UgPSBjYXNlX3doZW4oDQogICAgcmF0aW5nIDwgNSAmIHJhdGluZyA+PSA0IH4gIjQrIiwNCiAgICByYXRpbmcgPCA0ICYgcmF0aW5nID49IDMgfiAiMyB0byA0IiwNCiAgICByYXRpbmcgPCAzICYgcmF0aW5nID49IDIgfiAiMiB0byAzIiwNCiAgICByYXRpbmcgPCAyICYgcmF0aW5nID49IDEgfiAiMSB0byAyIiwNCiAgICByYXRpbmcgPCAxIH4gIj4xIiwNCiAgICBUUlVFIH4gIk5vIHJhdGluZyINCiAgKSkNCmBgYA0KDQojIyBESUZGSUNVTFRJRVMgV0lUSCBUSEUgREFUQQ0KDQpBZnRlciBoYXZpbmcgbGl0dGxlIHN1Y2Nlc3MgYXR0ZW1wdGluZyB0byBnZXQgYSBtb3JlIHVwIHRvIGRhdGUgZGF0YSBzZXQsIGkndmUgZGVjaWRlZCB0byBzdGljayB3aXRoIHdoYXQgSSBhbHJlYWR5IGhhdmUgLSBHaXZlbiBtb3JlIHRpbWUsIGkgd291bGQgaGF2ZSBsaWtlZA0KdG8gaGF2ZSBydW4gdGhlIHN0ZWFtL3N0ZWFtIHNweSBzY3JpcHQgdG8gc2NyYXBlIGFsbCB0aGUgc3RlYW0gZGF0YSwgYnV0IHVuZm9ydHVuYXRlbHkgaSBjb3VsZG4ndCBjb21taXQgMyBkYXlzIHRvIGl0Lg0KVGhlcmUgZG9lc24ndCBzZWVtIHRvIGJlIG11Y2ggaW4gdGhlIHdheSBvZiBtb2Rlcm4gc2FsZXMgZGF0YSwgd2l0aCBtb3N0IGNvbXBhbmllcyBub3QgcmVsZWFzaW5nIGZpZ3VyZXMgdW5sZXNzIGl0cyB0byBkbyB3aXRoIGEgbWlsZXN0b25lLg0KR2VucmVzIGFyZSBxdWl0ZSB2YWd1ZSAtIFdoaWxlIGl0IHdvdWxkIGJlIG5pY2UgdG8gaGF2ZSB0YWdzIGxpa2UgIk9wZW4gV29ybGQiLCAiUm91Z2UtbGlrZS9saXRlIiwgd2UgaW5zdGVhZCBtb3N0bHkgaGF2ZSAiQWN0aW9uIiAiQWR2ZW50dXJlIiwgIkluZGllIiwgd2hpY2gNCmFyZSBub3QgaHVnZWx5IGRlc2NyaXB0aXZlLiBUaGlzIG1pZ2h0IG1ha2UgcmVjb21tZW5kaW5nIGEgZ2VucmUgdG8gd29yayBvbiBoYXJkZXINCg0KLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLQ0KDQojIERBWSAzDQoNCmBgYHtyfQ0Kc2FsZXNfMjAxOSAlPiUgDQogIHN1bW1hcnkoKQ0KYGBgDQpBbGwgb2YgdGhlIFZHY2hhcnR6IHNjb3JlcyBhcmUgZW1wdHksIHNvIGl0IGNhbiBnby4gQWxzbywgc2FtZSBhcyBhYm92ZSwgdGhlcmUncyBubyBzdWNoIGdlbnJlIGFzIFBsYXRmb3JtDQoNCmBgYHtyfQ0Kc2FsZXNfMjAxOSA8LSBzYWxlc18yMDE5ICU+JSANCiAgY2xlYW5fbmFtZXMoKSAlPiUgDQogIHNlbGVjdCgtdmdfY2hhcnR6X3Njb3JlKSAlPiUgDQogIG11dGF0ZShnZW5yZSA9IGNhc2Vfd2hlbigNCiAgICBnZW5yZSA9PSAiUGxhdGZvcm0iIH4gIlBsYXRmb3JtZXIiLA0KICAgIFRSVUUgfiBnZW5yZQ0KICApKQ0KICANCmBgYA0KDQpgYGB7cn0NCmdhbWVzX3Jhdw0KYGBgDQoNCmBgYHtyfQ0Kc2FsZXNfMjAxOSAlPiUgDQogIGdyb3VwX2J5KG5hbWUpICU+JSANCiAgc3VtbWFyaXNlKHN1bSh0b3RhbF9zaGlwcGVkKSkgJT4lIA0KICBhcnJhbmdlKGRlc2MoYHN1bSh0b3RhbF9zaGlwcGVkKWApKSANCg0KIyB0b3RhbCBzaGlwcGVkIG1pZ2h0IG5vdCBiZSB0aGUgYmVzdCBtZXRyaWMgZm9yIHNhbGVzLCBidXQgYmV0dGVyIHRoYW4gbm90aGluZw0KYGBgDQoNCmBgYHtyfQ0Kc2FsZXNfMjAxOSAlPiUgDQogIGRpc3RpbmN0KHllYXIpICU+JSANCiAgYXJyYW5nZShkZXNjKHllYXIpKQ0KYGBgDQpgYGB7cn0NCnNhbGVzXzIwMTkgPC0gc2FsZXNfMjAxOSAlPiUgDQogIGZpbHRlcih5ZWFyICE9IDE5NzApDQpgYGANCg0KMTk3MCBpcyBub25zZW5zZS4gZHJvcHBpbmcgZW50aXJlIHllYXINCg0KYGBge3J9DQojIGFkZGluZyBjb2x1bW4gdG8gdXNlIGZvciBzaG93aW5nIHRyZW5kcyBvdmVyIHRpbWUNCnNhbGVzXzIwMTkgPC0gc2FsZXNfMjAxOSAlPiUgDQogIG11dGF0ZShmaXZlX3llYXJfcGVyaW9kID0gY2FzZV93aGVuKA0KICAgIHllYXIgPD0gMjAxOSAmIHllYXIgPj0gMjAxNCB+ICIyMDE0IC0gMjAxOSIsDQogICAgeWVhciA8PSAyMDEzICYgeWVhciA+PSAyMDA4IH4gIjIwMDggLSAyMDEzIiwNCiAgICB5ZWFyIDw9IDIwMDcgJiB5ZWFyID49IDIwMDIgfiAiMjAwMiAtIDIwMDciLA0KICAgIHllYXIgPD0gMjAwMSAmIHllYXIgPj0gMTk5NiB+ICIxOTk2IC0gMjAwMSIsDQogICAgeWVhciA8PSAxOTk1ICYgeWVhciA+PSAxOTkxIH4gIjE5OTEgLSAxOTk1IiwNCiAgICB5ZWFyIDw9IDE5OTAgJiB5ZWFyID49IDE5ODUgfiAiMTk4NSAtIDE5OTAiLA0KICAgIHllYXIgPD0gMTk4NCAmIHllYXIgPj0gMTk4MSB+ICIxOTgxIC0gMTk4NCIsDQogICAgeWVhciA8IDE5ODEgfiAiMTk4MCBhbmQgYmVmb3JlIiwNCiAgICBUUlVFIH4gInRoaXMgc2hvdWxkbnQgYXBwZWFyIg0KICApLCAuYWZ0ZXIgPSB5ZWFyKQ0KYGBgDQoNCmBgYHtyfQ0KIyBLRUVQIFRISVMgVklTVUFMSVNBVElPTg0Kc2FsZXNfMjAxOSAlPiUgDQogIGdyb3VwX2J5KGZpdmVfeWVhcl9wZXJpb2QpICU+JSANCiAgY291bnQoZ2VucmUpICU+JSANCiAgc2xpY2VfbWF4KG4gPSAyLCBuKSAlPiUgDQogIGdncGxvdChhZXMoeCA9IGZpdmVfeWVhcl9wZXJpb2QsIHkgPSBuLCBmaWxsID0gZ2VucmUpKSArDQogIGdlb21fY29sKGNvbG91ciA9ICJibGFjayIpICsNCiAgbGFicygNCiAgICB0aXRsZSA9ICJNb3N0IENvbW1vbiBHZW5yZXMgT3ZlciBUaW1lIiwNCiAgICBzdWJ0aXRsZSA9ICJTaG93biBvdmVyIDUgeWVhciBpbnRlcnZhbHMiLA0KICAgIGNhcHRpb24gPSAiRnJvbSAyMDE5IGdhbWVzIHNhbGVzIGRhdGEiDQogICkgKw0KICBzY2FsZV9maWxsX21hbnVhbCh2YWx1ZXMgPSBjKA0KICAgICJQbGF0Zm9ybWVyIiA9ICIjMDRFNzYyIiwNCiAgICAiQWN0aW9uIiA9ICIjREMwMDczIiwNCiAgICAiU3BvcnRzIiA9ICIjMDA4QkY4IiwNCiAgICAiTWlzYyIgPSAiI2Y1YjcwMCIsDQogICAgIlNob290ZXIiID0gIiMzOTAwOTkiDQogICkpICsNCiAgdGhlbWVfbGlnaHQoKSArDQogIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gMjUsIGhqdXN0ID0gMC41LCBzaXplID0gOSwgZmFjZSA9ICJib2xkIiwgdmp1c3QgPSAwLjgpKSArDQogIHRoZW1lKGF4aXMubGluZSA9IGVsZW1lbnRfbGluZShjb2xvdXIgPSAiYmxhY2siKSkrDQogIHRoZW1lKGF4aXMudGV4dC55ID0gZWxlbWVudF90ZXh0KHNpemUgPSA5LCBmYWNlID0gImJvbGQiKSkgKw0KICB4bGFiKCJJbnRlcnZhbCIpICsNCiAgeWxhYigiTnVtYmVyIG9mIEdhbWVzIGluIHRoZSBnZW5yZSByZWxlYXNlZCIpICsNCiAgdGhlbWUoYXhpcy50aXRsZS54ID0gZWxlbWVudF90ZXh0KGZhY2UgPSAiaXRhbGljIiwgc2l6ZSA9IDEwKSkgKw0KICB0aGVtZShheGlzLnRpdGxlLnkgPSBlbGVtZW50X3RleHQoZmFjZSA9ICJpdGFsaWMiLCBzaXplID0gMTApKSArDQogIHRoZW1lKHBsb3QuY2FwdGlvbiA9IGVsZW1lbnRfdGV4dChzaXplID0gNywgaGp1c3QgPSAxLjI1KSkgKw0KICBsYWJzKGZpbGwgPSAiR2VucmUiKQ0KDQojIE1pc2MgaXNudCB2ZXJ5IGRlc2NyaXB0aXZlIG9yIGhlbHBmdWwgLSBpbiB0ZXJtcyBvZiByZWNvbW1lbmRpbmcgbWFraW5nIHNvbWV0aGluZyB0byBzb21lb25lIGl0IG1lYW5zIGVzc2VudGlhbGx5ICJ0cnkgYW55dGhpbmciDQoNCiMgZ2dzYXZlKCJWaXN1YWxpc2F0aW9ucy8yMDE5X2dlbnJlc19pbmNfbWlzYy5wbmciKQ0KYGBgDQoNCmBgYHtyfQ0KDQojIFBMT1QgU0hPV0lORyBNT1NUIENPTU1PTiBHRU5SRSBPRiBHQU1FUyAtIE5PVCBORUNFU1NBUklMWSBCRVNUIFNFTExJTkcNCiMgS0VFUCBUSElTIFZJU1VBTElTQVRJT04NCnNhbGVzXzIwMTkgJT4lIA0KICBncm91cF9ieShmaXZlX3llYXJfcGVyaW9kKSAlPiUgDQogIGZpbHRlcihnZW5yZSAhPSAiTWlzYyIpICU+JSANCiAgY291bnQoZ2VucmUpICU+JSANCiAgc2xpY2VfbWF4KG4gPSAyLCBuKSAlPiUgDQogIGdncGxvdChhZXMoeCA9IGZpdmVfeWVhcl9wZXJpb2QsIHkgPSBuLCBmaWxsID0gZ2VucmUpKSArDQogIGdlb21fY29sKGNvbG91ciA9ICJibGFjayIpICsNCiAgbGFicygNCiAgICB0aXRsZSA9ICJNb3N0IENvbW1vbiBHZW5yZXMgT3ZlciBUaW1lIiwNCiAgICBzdWJ0aXRsZSA9ICJTaG93biBvdmVyIDUgeWVhciBpbnRlcnZhbHMgLSBFeGNsdWRpbmcgJ01pc2MnIGdlbnJlIiwNCiAgICBjYXB0aW9uID0gIkZyb20gMjAxOSBnYW1lIHNhbGVzIGRhdGEiDQogICkgKw0KICAgc2NhbGVfZmlsbF9tYW51YWwodmFsdWVzID0gYygNCiAgICJQbGF0Zm9ybWVyIiA9ICIjMDRFNzYyIiwNCiAgICAiQWN0aW9uIiA9ICIjREMwMDczIiwNCiAgICAiU3BvcnRzIiA9ICIjMDA4QkY4IiwNCiAgICMgIk1pc2MiID0gIiNmNWI3MDAiLA0KICAgICJTaG9vdGVyIiA9ICIjMzkwMDk5IiwNCiAgICAiQWR2ZW50dXJlIiA9ICIjOGFjOTI2IiwNCiAgICAiUm9sZS1QbGF5aW5nIiA9ICIjZmY2YjM1Ig0KICAgKSkgKw0KICB0aGVtZV9saWdodCgpICsNCiAgdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSAyNSwgaGp1c3QgPSAwLjUsIHNpemUgPSA5LCBmYWNlID0gImJvbGQiLCB2anVzdCA9IDAuOCkpICsNCiAgdGhlbWUoYXhpcy5saW5lID0gZWxlbWVudF9saW5lKGNvbG91ciA9ICJibGFjayIpKSsNCiAgdGhlbWUoYXhpcy50ZXh0LnkgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDksIGZhY2UgPSAiYm9sZCIpKSArDQogIHhsYWIoIkludGVydmFsIikgKw0KICB5bGFiKCJOdW1iZXIgb2YgR2FtZXMgaW4gdGhlIGdlbnJlIHJlbGVhc2VkIikgKw0KICB0aGVtZShheGlzLnRpdGxlLnggPSBlbGVtZW50X3RleHQoZmFjZSA9ICJpdGFsaWMiLCBzaXplID0gMTApKSArDQogIHRoZW1lKGF4aXMudGl0bGUueSA9IGVsZW1lbnRfdGV4dChmYWNlID0gIml0YWxpYyIsIHNpemUgPSAxMCkpICsNCiAgdGhlbWUocGxvdC5jYXB0aW9uID0gZWxlbWVudF90ZXh0KHNpemUgPSA3LCBoanVzdCA9IDEuMjUpKSArDQogIGxhYnMoZmlsbCA9ICJHZW5yZSIpDQogICANCg0KIyBnZ3NhdmUoIlZpc3VhbGlzYXRpb25zLzIwMTlfZ2VucmVzX2V4Y2xfbWlzYy5wbmciKSAgICAgIA0KYGBgDQoNCmBgYHtyfQ0Kc2FsZXNfMjAxOSAlPiUgDQogIGZpbHRlcihmaXZlX3llYXJfcGVyaW9kID09ICIyMDE5IC0gMjAxNCIpICU+JSANCiAgZmlsdGVyKGdlbnJlID09ICJNaXNjIikNCmBgYA0KVGhpcyBpcyBzbGlnaHRseSBjb25jZXJuaW5nIC0gYSBsb3Qgb2YgdGhlc2UgdGl0bGVzIGNvdWxkIGVhc2lseSBoYXZlIGEgZ2VucmUgdGhhdCBpc24ndCB0aGUgY3VyZS1hbGwgIk1pc2MiIC0gDQpJbmNsdWRlIGJvdGggZ3JhcGhzIC0gb25lIHdpdGggbWlzYywgb25lIGV4Y2x1ZGluZyBpdA0KDQpgYGB7cn0NCmdhbWVzX3JhdyAlPiUgDQogIGZpbHRlcihnZW5yZSA9PSAiTWlzYyIpDQpgYGANCldoYXQgYWJvdXQgYSBzaW1pbGFyIHBsb3QgZm9yIHN0ZWFtIGdhbWVzPw0KDQpgYGB7cn0NCnN0ZWFtDQpgYGANCmBgYHtyfQ0Kc3RlYW1feWVhcnMgPC0gc3RlYW0gJT4lIA0KICBtdXRhdGUocmVsZWFzZV95ZWFyID0geWVhcihyZWxlYXNlX2RhdGUpLC5hZnRlciA9IHJlbGVhc2VfZGF0ZSkNCmBgYA0KYGBge3J9DQpzdGVhbV95ZWFycyAlPiUgDQogIG11dGF0ZShsZW5ndGhfZ2VucmUgPSBuY2hhcihnZW5yZXMpLC5hZnRlciA9IG5hbWUpICU+JSANCiAgYXJyYW5nZShkZXNjKGxlbmd0aF9nZW5yZSkpDQpgYGANCg0KYGBge3J9DQpzdGVhbV95ZWFycyAlPiUgDQogIGRpc3RpbmN0KHJlbGVhc2VfeWVhcikgJT4lIA0KICBhcnJhbmdlKGRlc2MocmVsZWFzZV95ZWFyKSkNCmBgYA0KYGBge3J9DQpzdGVhbV95ZWFycyA8LSBzdGVhbV95ZWFycyAlPiUgIA0KICBzZXBhcmF0ZShjb2wgPSBnZW5yZXMsIHNlcCA9ICI7IiwgaW50byA9IHBhc3RlMCgiR2VucmUiLCBzZXFfbGVuKG1heChuY2hhciguJGdlbnJlcykpKSkpICU+JSAgIyB0aGlzIGlzIGFic29sdXRlbHkgaG9ycmVuZG91cywgYnV0IGl0IGdldHMgbWUgYWxsIHRoZSBnZW5yZXMgaW50byBzZXBhcmF0ZSBjb2x1bW5zIHNvIHdoYXRldmVyDQogIHNlbGVjdCgtR2VucmUxNDotR2VucmUxODApICU+JSANCiAgcGl2b3RfbG9uZ2VyKGNvbHMgPSBHZW5yZTE6R2VucmUxMywgbmFtZXNfdG8gPSAiZ2VucmVzIikgJT4lIA0KICBkcm9wX25hKHZhbHVlKSAlPiUgIyBvayBub3cgd2UgY2FuIG1ha2UgdGhlIHllYXIgaW50ZXJ2YWxzIGFuZCBncm91cCB0aGVtIHRvIGZpbmQgd2hhdCBnZW5yZXMgd2VyZSBwb3B1bGFyIA0KICBtdXRhdGUoeWVhcl9yYW5nZSA9IGNhc2Vfd2hlbigNCiAgICByZWxlYXNlX3llYXIgPD0gMjAxOSAmIHJlbGVhc2VfeWVhciA+PSAyMDE2IH4gIjIwMTYgLSAyMDE5IiwNCiAgICByZWxlYXNlX3llYXIgPD0gMjAxNSAmIHJlbGVhc2VfeWVhciA+PSAyMDEyIH4gIjIwMTIgLSAyMDE1IiwNCiAgICByZWxlYXNlX3llYXIgPD0gMjAxMSAmIHJlbGVhc2VfeWVhciA+PSAyMDA5IH4gIjIwMDkgLSAyMDExIiwNCiAgICByZWxlYXNlX3llYXIgPD0gMjAwOCAmIHJlbGVhc2VfeWVhciA+PSAyMDA1IH4gIjIwMDUgLSAyMDA4IiwNCiAgICByZWxlYXNlX3llYXIgPD0gMjAwNCAmIHJlbGVhc2VfeWVhcj49IDIwMDAgfiAiMjAwMCAtIDIwMDQiLA0KICAgIHJlbGVhc2VfeWVhciA8IDIwMDEgfiAiQmVmb3JlIDIwMDAiLA0KICAgIFRSVUUgfiAidGhpcyBzaG91bGRudCBhcHBlYXIiDQogICksLmFmdGVyID0gcmVsZWFzZV95ZWFyKSANCmBgYA0KDQpgYGB7cn0NCnN0ZWFtX3llYXJzICU+JSANCiAgZmlsdGVyKHllYXJfcmFuZ2UgPT0gIjIwMDAgLSAyMDA0IikNCmBgYA0KYGBge3J9DQpzdGVhbV95ZWFycyAlPiUgDQogIGdyb3VwX2J5KHllYXJfcmFuZ2UpICU+JSANCiAgY291bnQodmFsdWUpICU+JSANCiAgc2xpY2VfbWF4KG4gPSAyLCBuKSAlPiUgDQogIGFycmFuZ2UoZGVzYyhuKSkgICU+JSANCiAgZmlsdGVyKHllYXJfcmFuZ2UgIT0gIkJlZm9yZSAyMDAwIikgJT4lIA0KICBnZ3Bsb3QoYWVzKHggPSB5ZWFyX3JhbmdlLCB5ID0gbiwgZmlsbCA9IHZhbHVlKSkgKw0KICBnZW9tX2NvbChjb2xvdXIgPSAiYmxhY2siKSArDQogIGxhYnMoDQogICAgdGl0bGUgPSAiTW9zdCBDb21tb24gR2VucmVzIE92ZXIgVGltZSIsDQogICAgc3VidGl0bGUgPSAiU2hvd24gb3ZlciAzLTQgeWVhciBpbnRlcnZhbHMiLA0KICAgIGNhcHRpb24gPSAiRnJvbSAyMDE5IFN0ZWFtL1N0ZWFtIFNweSBkYXRhIg0KICApICsNCiAgc2NhbGVfZmlsbF9tYW51YWwodmFsdWVzID0gYygNCiAgICAiSW5kaWUiID0gIiMwNEU3NjIiLA0KICAgICJBY3Rpb24iID0gIiNEQzAwNzMiDQogICkpICsNCiAgdGhlbWVfbGlnaHQoKSArDQogIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gMjUsIGhqdXN0ID0gMC41LCBzaXplID0gOSwgZmFjZSA9ICJib2xkIiwgdmp1c3QgPSAwLjgpKSArDQogIHRoZW1lKGF4aXMubGluZSA9IGVsZW1lbnRfbGluZShjb2xvdXIgPSAiYmxhY2siKSkrDQogIHRoZW1lKGF4aXMudGV4dC55ID0gZWxlbWVudF90ZXh0KHNpemUgPSA5LCBmYWNlID0gImJvbGQiKSkgKw0KICB4bGFiKCJJbnRlcnZhbCIpICsNCiAgeWxhYigiTnVtYmVyIG9mIEdhbWVzIGluIHRoZSBnZW5yZSByZWxlYXNlZCIpICsNCiAgdGhlbWUoYXhpcy50aXRsZS54ID0gZWxlbWVudF90ZXh0KGZhY2UgPSAiaXRhbGljIiwgc2l6ZSA9IDEwKSkgKw0KICB0aGVtZShheGlzLnRpdGxlLnkgPSBlbGVtZW50X3RleHQoZmFjZSA9ICJpdGFsaWMiLCBzaXplID0gMTApKSArDQogIHRoZW1lKHBsb3QuY2FwdGlvbiA9IGVsZW1lbnRfdGV4dChzaXplID0gNywgaGp1c3QgPSAxLjI1KSkgKw0KICBsYWJzKGZpbGwgPSAiR2VucmUiKQ0KYGBgDQoNCmBgYHtyfQ0KIyBIYXBweSB3aXRoIHRoaXMgb25lIGFzIGEgY29tcGFyaXNvbiBwb2ludA0Kc3RlYW1feWVhcnMgJT4lIA0KICBmaWx0ZXIocmVsZWFzZV95ZWFyID49IDIwMDkpICU+JSANCiAgZ3JvdXBfYnkocmVsZWFzZV95ZWFyKSAlPiUgDQogIGNvdW50KHZhbHVlKSAlPiUgDQogIHNsaWNlX21heChuID0gMiwgbikgJT4lIA0KICBhcnJhbmdlKGRlc2MobikpICAlPiUgDQogIGdncGxvdChhZXMoeCA9IHJlbGVhc2VfeWVhciwgeSA9IG4sIGZpbGwgPSB2YWx1ZSkpICsNCiAgZ2VvbV9jb2woY29sb3VyID0gImJsYWNrIikgKw0KICBsYWJzKA0KICAgIHRpdGxlID0gIk1vc3QgQ29tbW9uIEdlbnJlcyBPdmVyIFRpbWUiLA0KICAgIHN1YnRpdGxlID0gIlNob3duIHllYXIgYnkgeWVhciBmcm9tIDIwMDkgdW50aWwgTWF5IDIwMTkiLA0KICAgIGNhcHRpb24gPSAiRnJvbSAyMDE5IFN0ZWFtL1N0ZWFtIFNweSBkYXRhIg0KICApICsNCiAgIHNjYWxlX2ZpbGxfbWFudWFsKHZhbHVlcyA9IGMoDQogICAgICJJbmRpZSIgPSAiIzA0RTc2MiIsDQogICAgICJBY3Rpb24iID0gIiNEQzAwNzMiLA0KICAgICAiQ2FzdWFsIiA9ICIjMDA4QkY4IiwNCiAgICAgIkFkdmVudHVyZSIgPSAiI2Y1YjcwMCINCiAgICkpICsNCiAgdGhlbWVfbGlnaHQoKSArDQogIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gMjUsIGhqdXN0ID0gMC41LCBzaXplID0gOSwgZmFjZSA9ICJib2xkIiwgdmp1c3QgPSAwLjgpKSArDQogIHRoZW1lKGF4aXMubGluZSA9IGVsZW1lbnRfbGluZShjb2xvdXIgPSAiYmxhY2siKSkrDQogIHRoZW1lKGF4aXMudGV4dC55ID0gZWxlbWVudF90ZXh0KHNpemUgPSA5LCBmYWNlID0gImJvbGQiKSkgKw0KICB4bGFiKCJJbnRlcnZhbCIpICsNCiAgeWxhYigiTnVtYmVyIG9mIEdhbWVzIGluIHRoZSBnZW5yZSByZWxlYXNlZCIpICsNCiAgdGhlbWUoYXhpcy50aXRsZS54ID0gZWxlbWVudF90ZXh0KGZhY2UgPSAiaXRhbGljIiwgc2l6ZSA9IDEwKSkgKw0KICB0aGVtZShheGlzLnRpdGxlLnkgPSBlbGVtZW50X3RleHQoZmFjZSA9ICJpdGFsaWMiLCBzaXplID0gMTApKSArDQogIHRoZW1lKHBsb3QuY2FwdGlvbiA9IGVsZW1lbnRfdGV4dChzaXplID0gNywgaGp1c3QgPSAxLjI1KSkgKw0KICBzY2FsZV94X2NvbnRpbnVvdXMoYnJlYWtzID0gYygyMDA5LCAyMDEwLCAyMDExLCAyMDEyLCAyMDEzLCAyMDE0LCAyMDE1LCAyMDE2LCAyMDE3LCAyMDE4LCAyMDE5KSkgKw0KICBsYWJzKGZpbGwgPSAiR2VucmUiKQ0KDQojIGdnc2F2ZSgiVmlzdWFsaXNhdGlvbnMvc3RlYW1fZ2VucmVzXzIwMDlfb24ucG5nIikNCmBgYA0KDQoNCmBgYHtyfQ0Kc3RlYW1feWVhcnMgJT4lIA0KICBmaWx0ZXIocmVsZWFzZV95ZWFyID09IDIwMTkpDQpgYGANCg0KDQpgYGB7cn0NCnN0ZWFtX3llYXJzICU+JSANCiAgbXV0YXRlKG1vbnRoID0gbW9udGgocmVsZWFzZV9kYXRlKSkgJT4lIA0KICBmaWx0ZXIocmVsZWFzZV95ZWFyID09IDIwMTkpICU+JSANCiAgc2VsZWN0KG1vbnRoKSAlPiUgDQogIGFycmFuZ2UoZGVzYyhtb250aCkpDQpgYGANCmBgYHtyfQ0KYmFja2xvZ2dkDQpgYGANCg0KYGBge3J9DQpiYWNrbG9nZ2RfZ2VucmVzIDwtIGJhY2tsb2dnZCAlPiUgDQogIHBpdm90X2xvbmdlcihjb2xzID0gZ2VucmVfdGFnOmdlbnJlX3RhZ183LCBuYW1lc190byA9ICJsaXN0IiwgdmFsdWVzX3RvID0gImdlbnJlIikgJT4lIA0KICBkcm9wX25hKGdlbnJlKQ0KYGBgDQoNCmBgYHtyfQ0KIyBvayBub3cgaSd2ZSBkZWZpbml0ZWx5IGdvdHRlbiByaWQgb2YgZXZlcnl0aGluZyB0aGF0IGhhc250IHJlbGVhc2VkDQpiYWNrbG9nZ2RfZ2VucmVzIDwtIGJhY2tsb2dnZF9nZW5yZXMgJT4lIA0KICBtdXRhdGUocmVsZWFzZV95ZWFyID0geWVhcihyZWxlYXNlX2RhdGUpKSAlPiUgDQogIGZpbHRlcigteWVhcnNfc2luY2VfcmVsZWFzZSA8IDAuMDEpDQpgYGANCg0KYGBge3J9DQpiYWNrbG9nZ2RfZ2VucmVzICU+JSANCiAgZGlzdGluY3QocmVsZWFzZV95ZWFyKSAlPiUgDQogIGFycmFuZ2UoZGVzYyhyZWxlYXNlX3llYXIpKQ0KYGBgDQpgYGB7cn0NCmJhY2tsb2dnZF9nZW5yZXMgPC0gYmFja2xvZ2dkX2dlbnJlcyAlPiUgICANCiAgbXV0YXRlKGludGVydmFscyA9IGNhc2Vfd2hlbigNCiAgIHJlbGVhc2VfeWVhciA8PSAyMDIzICYgcmVsZWFzZV95ZWFyID49IDIwMjAgfiAiMjAyMCAtIDIwMjMiLA0KICAgIHJlbGVhc2VfeWVhciA8PSAyMDE5ICYgcmVsZWFzZV95ZWFyID49IDIwMTQgfiAiMjAxNCAtIDIwMTkiLA0KICAgIHJlbGVhc2VfeWVhciA8PSAyMDEzICYgcmVsZWFzZV95ZWFyID49IDIwMDggfiAiMjAwOCAtIDIwMTMiLA0KICAgIHJlbGVhc2VfeWVhciAgPD0gMjAwNyAmIHJlbGVhc2VfeWVhciAgPj0gMjAwMiB+ICIyMDAyIC0gMjAwNyIsDQogICAgcmVsZWFzZV95ZWFyICA8PSAyMDAxICYgcmVsZWFzZV95ZWFyICA+PSAxOTk2IH4gIjE5OTYgLSAyMDAxIiwNCiAgICByZWxlYXNlX3llYXIgIDw9IDE5OTUgJiByZWxlYXNlX3llYXIgID49IDE5OTEgfiAiMTk5MSAtIDE5OTUiLA0KICAgIHJlbGVhc2VfeWVhciAgPD0gMTk5MCAmIHJlbGVhc2VfeWVhciAgPj0gMTk4NSB+ICIxOTg1IC0gMTk5MCIsDQogICAgcmVsZWFzZV95ZWFyICA8PSAxOTg0ICYgcmVsZWFzZV95ZWFyICA+PSAxOTgxIH4gIjE5ODEgLSAxOTg0IiwNCiAgICByZWxlYXNlX3llYXIgIDwgMTk4MSB+ICIxOTgwIGFuZCBiZWZvcmUiLA0KICAgIFRSVUUgfiAidGhpcyBzaG91bGRudCBhcHBlYXIiDQogICkpIA0KYGBgDQoNCmBgYHtyfQ0KIyBUaGlzIGlzbid0IHNob3dpbmcgdGhlIG1vc3QgcG9wdWxhciBnZW5yZXMgaW4gYSB0aW1lZnJhbWUsIG1vcmUgb2YgYW4gaW5zaWdodCBpbnRvIHdoYXQgcGVvcGxlIGFyZSBwbGF5aW5nDQojIEdyYW50ZWQsIEJhY2tsb2dnZCBpc24ndCB0aGUgYmlnZ2VzdCBzZXJ2aWNlIGluIHRoZSB3b3JsZCwgYnV0IGl0J3MgYSBnb29kIGlkZWEgb2Ygd2hhdCBwZW9wbGUgbGlrZSwgYW5kIHN0aWxsIHBsYXkNCmJhY2tsb2dnZF9nZW5yZXMgJT4lIA0KICBtdXRhdGUoZ2VucmUgPSBjYXNlX3doZW4oDQogICAgZ2VucmUgPT0gIlBsYXRmb3JtIiB+ICJQbGF0Zm9ybWVyIiwNCiAgICBUUlVFIH4gZ2VucmUNCiAgKSkgJT4lDQogIGZpbHRlcihpbnRlcnZhbHMgIT0gIjE5ODAgYW5kIGJlZm9yZSIpICU+JSANCiAgZmlsdGVyKGludGVydmFscyAhPSAiMTk4MSAtIDE5ODQiKSAlPiUgDQogIGdyb3VwX2J5KGludGVydmFscykgJT4lIA0KICBjb3VudChnZW5yZSkgJT4lIA0KICBzbGljZV9tYXgobiA9IDIsIG4pICU+JSANCiAgZ2dwbG90KGFlcyh4ID0gaW50ZXJ2YWxzLCB5ID0gbiwgZmlsbCA9IGdlbnJlKSkgKw0KICBnZW9tX2NvbChjb2xvdXIgPSAiYmxhY2siKSArDQogICBsYWJzKA0KICAgICB0aXRsZSA9ICJXaGF0IGRvIHBlb3BsZSBzdGlsbCBwbGF5PyIsDQogICAgIHN1YnRpdGxlID0gIlNwbGl0IGludG8gR2VucmUgYW5kIFJlbGVhc2UgWWVhciIsDQogICAgIGNhcHRpb24gPSAiRnJvbSBNYXJjaCAyMDIzIEJhY2tsb2dnZCBkYXRhIg0KICAgKSArDQogICBzY2FsZV9maWxsX21hbnVhbCh2YWx1ZXMgPSBjKA0KICAgIlBsYXRmb3JtZXIiID0gIiMwNEU3NjIiLA0KICAgIyJBY3Rpb24iID0gIiNEQzAwNzMiLA0KICAgIyJTcG9ydHMiID0gIiMwMDhCRjgiLA0KICAgIyJNaXNjIiA9ICIjZjViNzAwIiwNCiAgICJTaG9vdGVyIiA9ICIjMzkwMDk5IiwNCiAgICJBZHZlbnR1cmUiID0gIiM4YWM5MjYiLA0KICAgIlJQRyIgPSAiI2ZmNmIzNSINCiAgICkpICsNCiAgIHRoZW1lX2xpZ2h0KCkgKw0KICAgdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSAyNSwgaGp1c3QgPSAwLjUsIHNpemUgPSA5LCBmYWNlID0gImJvbGQiLCB2anVzdCA9IDAuOCkpICsNCiAgIHRoZW1lKGF4aXMubGluZSA9IGVsZW1lbnRfbGluZShjb2xvdXIgPSAiYmxhY2siKSkrDQogICB0aGVtZShheGlzLnRleHQueSA9IGVsZW1lbnRfdGV4dChzaXplID0gOSwgZmFjZSA9ICJib2xkIikpICsNCiAgIHhsYWIoIlJlbGVhc2Ugd2luZG93IikgKw0KICAgeWxhYigiSG93IG1hbnkgcGVvcGxlIGhhdmUgcGxheWVkICIpICsNCiAgIHRoZW1lKGF4aXMudGl0bGUueCA9IGVsZW1lbnRfdGV4dChmYWNlID0gIml0YWxpYyIsIHNpemUgPSAxMCkpICsNCiAgIHRoZW1lKGF4aXMudGl0bGUueSA9IGVsZW1lbnRfdGV4dChmYWNlID0gIml0YWxpYyIsIHNpemUgPSAxMCkpICsNCiAgIHRoZW1lKHBsb3QuY2FwdGlvbiA9IGVsZW1lbnRfdGV4dChzaXplID0gNywgaGp1c3QgPSAxLjI1KSkgKw0KICAgbGFicyhmaWxsID0gIkdlbnJlIikNCg0KIyBnZ3NhdmUoIlZpc3VhbGlzYXRpb25zL2JhY2tsb2dnZF9nZW5yZXMucG5nIikNCmBgYA0KDQojIFdlIGhhdmUgZXN0YWJsaXNoZWQgdGhhdCBJbmRpZSwgQWN0aW9uIGFuZCBBZHZlbnR1cmUgZ2FtZXMgc2VlbSB0byBiZSB0aGUgbW9zdCBwb3B1bGFyIC0gQnV0IHdoYXQgb3RoZXIgZWxlbWVudHMgbWFrZSB0aGVtIHBvcHVsYXI/DQoNCiMjIE5vdGU6IEFjdGlvbiBhbmQgQWR2ZW50dXJlIGFyZSBwcmV0dHkgaW50ZXJjaGFuZ2FibGUgbm90aGluZyB0ZXJtcyB0aGF0IGRlc2NyaWJlIGxpa2UgOTAlIG9mIHRpdGxlcyBidXQgb2ggd2VsbA0KIyMjIExpa2Ugd291bGQgeW91IGNvbXBhcmUgTmllciBBdXRvbWF0YSB0byBEb25rZXkgS29uZyBKdW5nbGUgQmVhdD8gSSB3b3VsZG4ndCBidXQgd2hvIGFtIGkgdG8gc2F5DQoNCmBgYHtyfQ0Kc3RlYW1fcG9zX2FhaSA8LSBzdGVhbV95ZWFycyAlPiUgDQogIGZpbHRlcihnZW5lcmFsX3JhdGluZyA9PSAiRXh0cmVtZWx5IFBvc2l0aXZlIiB8IGdlbmVyYWxfcmF0aW5nID09ICJQb3NpdGl2ZSIpICU+JSANCiAgZ3JvdXBfYnkobmFtZSkgJT4lIA0KICBmaWx0ZXIoYW55KHZhbHVlICVpbiUgYygiSW5kaWUiLCAiQWN0aW9uIiwgIkFkdmVudHVyZSIpKSkgDQpgYGANCg0KYGBge3J9DQp3cml0ZV9jc3Yoc3RlYW1fcG9zX2FhaSwgImNsZWFuX2RhdGEvc3RlYW1fcG9zaXRpdmVfcmF0aW5nc19hYWkuY3N2IikNCmBgYA0KDQphbmQgZm9yIGNvbXBhcmlzb24NCg0KYGBge3J9DQpzdGVhbV9wb3MgPC0gc3RlYW1feWVhcnMgJT4lIA0KICBmaWx0ZXIoZ2VuZXJhbF9yYXRpbmcgPT0gIkV4dHJlbWVseSBQb3NpdGl2ZSIgfCBnZW5lcmFsX3JhdGluZyA9PSAiUG9zaXRpdmUiKSAlPiUgDQogIGdyb3VwX2J5KG5hbWUpDQpgYGANCg0KYGBge3J9DQpzdGVhbV9wb3NfYWFpDQpgYGANCg0KYGBge3J9DQp3cml0ZV9jc3Yoc3RlYW1fcG9zLCAiY2xlYW5fZGF0YS9zdGVhbV9wb3NpdGl2ZV9yYXRpbmdzLmNzdiIpDQpgYGANCg0KIyBNYWtlIGEgbW9kZWwgdGhhdCB0cmllcyB0byBndWVzcyBpZiBhIGdhbWUgaXMgcG9zaXRpdmVseSByYXRlZD8NCg0KIyBgYGB7cn0NCiMgc3RlYW1fbW9kZWxfYmFzZSA8LSBzdGVhbSAlPiUgDQojICAgc2VwYXJhdGUoY29sID0gZ2VucmVzLCBzZXAgPSAiOyIsIGludG8gPSBwYXN0ZTAoIkdlbnJlIiwgc2VxX2xlbihtYXgobmNoYXIoLiRnZW5yZXMpKSkpKSAlPiUgDQojICAgc2VsZWN0KC1HZW5yZTE0Oi1HZW5yZTE4MCkNCiMgYGBgDQojIGBgYHtyfQ0KIyBzdGVhbV9tb2RlbF9iYXNlICU+JSANCiMgICBzZXBhcmF0ZShjb2wgPSBjYXRlZ29yaWVzLCBzZXAgPSAiOyIsIGludG8gPSBwYXN0ZTAoImNhdGVnb3JpZXMiLCBzZXFfbGVuKG1heChuY2hhciguJGNhdGVnb3JpZXMpKSkpKSAlPiUgDQojICAgc2VsZWN0KC1jYXRlZ29yaWVzMjE6LWNhdGVnb3JpZXMyOTkpDQojIGBgYA0KIyANCiMgYGBge3J9DQojIHN0ZWFtICU+JSANCiMgICBzZWxlY3QoY2F0ZWdvcmllcykgJT4lIA0KIyAgbXV0YXRlKGxlbmd0aF9jYXQgPSBuY2hhcihjYXRlZ29yaWVzKSkgJT4lIA0KIyAgIGFycmFuZ2UoZGVzYyhsZW5ndGhfY2F0KSkNCiMgYGBgDQoNClRoaXMgaXMgaWRpb3RpYy4gVGhlcmUgYXJlIGZhciB0b28gbWFueSB2YXJpYWJsZXMuIE1pZ2h0IG11dGF0ZSBhIGZldyBvZiB0aGVzZSBpbnRvIGxvZ2ljYWxzLCBsaWtlIGNvbnRyb2xsZXIgc3VwcG9ydA0KDQpfX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX18NCg0KYGBge3J9DQpzdGVhbSA8LSBzdGVhbSAlPiUgDQogIG11dGF0ZShjb250cm9sbGVyX3N1cHBvcnQgPSBjYXNlX3doZW4oDQogICAgc3RyX2RldGVjdChjYXRlZ29yaWVzLCAiRnVsbCBjb250cm9sbGVyIHN1cHBvcnQiKSB+ICJGdWxsIiwNCiAgICBzdHJfZGV0ZWN0KGNhdGVnb3JpZXMsICJQYXJ0aWFsIENvbnRyb2xsZXIgc3VwcG9ydCIpIH4gIlBhcnRpYWwiLA0KICAgIFRSVUUgfiAiTm8iDQogICksLmFmdGVyID0gdmlydHVhbF9yZWFsaXR5X3N1cHBvcnQpDQpgYGANCg0KYGBge3J9DQpzdGVhbSA8LSBzdGVhbSAlPiUgDQogIG11dGF0ZShzdGVhbV93b3Jrc2hvcCA9IGNhc2Vfd2hlbigNCiAgICBzdHJfZGV0ZWN0KGNhdGVnb3JpZXMsICJTdGVhbSBXb3Jrc2hvcCIpIH4gVFJVRSwNCiAgICBUUlVFIH4gRkFMU0UNCiAgKSwuYWZ0ZXIgPSBjb250cm9sbGVyX3N1cHBvcnQpIA0KYGBgDQoNCmBgYHtyfQ0Kc3RlYW0NCmBgYA0KDQpgYGB7cn0NCndyaXRlX2NzdihzdGVhbSwgInJhd19kYXRhL3N0ZWFtX2NoZWNrcG9pbnRfMi5jc3YiKQ0KYGBgDQoNCk9rIHNvIHdoYXQgZG8gaSBuZWVkIHRvIGRvIHRvbW9ycm93IC0gQ29udGludWUgd29ya2luZyBvbiB2aXN1YWxpc2F0aW9ucywgbWF5YmUgbWFrZSBhIG1vZGVsIHRoYXQgdHJpZXMgdG8gc2VlIHdoYXQgZmFjdG9ycyBtYWtlIGdhbWVzIGRvIHdlbGwgb24gc3RlYW0/